﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.IO.Compression;
using System.Runtime.Serialization.Formatters.Binary;
using System.Data;
using System.Runtime.Serialization;
using System.Collections.ObjectModel;
using System.Reflection;

namespace Blank.Extends
{
    public static class DataTableExtends
    {
        /// <summary>
        /// 将DataRow 转换为一个实体对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dr"></param>
        /// <returns></returns>
        public static T GetEntity<T>(this DataRow dr)
        {
            return dr.GetEntity<T>(dr.Table.Columns.Count);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dr"></param>
        /// <param name="columnCount"></param>
        /// <returns></returns>
        internal static T GetEntity<T>(this DataRow dr, int columnCount)
        {
            return dr.GetEntity<T>(columnCount, dr.Table.Columns);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dr"></param>
        /// <param name="columnCount"></param>
        /// <param name="Columns"></param>
        /// <returns></returns>
        internal static T GetEntity<T>(this DataRow dr, int columnCount, DataColumnCollection Columns)
        {
            try
            {
                T element = Activator.CreateInstance<T>();
                for (int i = 0; i < columnCount; i++)
                {
                    PropertyInfo property = typeof(T).GetProperty(Columns[i].ColumnName, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public);
                    if (property != null)
                    {
                        object obj = dr[property.Name];
                        if (obj == DBNull.Value)
                            property.SetValue(element, null, null);
                        else
                            property.SetValue(element, Convert.ChangeType(obj, property.PropertyType), null);
                    }
                }
                return element;
            }
            catch (Exception e)
            {
                throw new Exception("err:DataRow Convert to Entity Failed", e);
            }
        }
        /// <summary>
        /// 将DataTable转换成一个动态数据集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="table"></param>
        /// <returns></returns>
        public static ObservableCollection<T> GetObservableCollection<T>(this DataTable table)
        {
            ObservableCollection<T> lists = new ObservableCollection<T>();
            DataColumnCollection Columns = table.Columns;
            int columnCount = Columns.Count;
            foreach (DataRow dr in table.Rows)
            {
                lists.Add(dr.GetEntity<T>(columnCount, Columns));
            }
            return lists.Count > 0 ? lists : null;
        }
        /// <summary>
        /// 将DataTable转换成一个List集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="table"></param>
        /// <returns></returns>
        public static List<T> GetList<T>(this DataTable table)
        {
            List<T> lists = new List<T>();
            DataColumnCollection Columns = table.Columns;
            int columnCount = Columns.Count;
            foreach (DataRow dr in table.Rows)
            {
                lists.Add(dr.GetEntity<T>(columnCount, Columns));
            }
            return lists.Count > 0 ? lists : null;
        }
        /// <summary>
        /// 序列化DataTable对象并压缩
        /// </summary>
        /// <param name="table"></param>
        /// <returns></returns>
        public static string CompressDataTableToString(this DataTable table)
        {
            if (table == null) { return ""; }
            else
            {
                try
                {
                    IFormatter formatter = new BinaryFormatter();//定义BinaryFormatter以序列化DataTable对象
                    using (MemoryStream formatterMs = new MemoryStream())
                    {
                        //序列化DataTable对象到一内存流里
                        formatter.Serialize(formatterMs, table);
                        using (MemoryStream compressMs = new MemoryStream())
                        {
                            // gzip压缩
                            using (GZipStream gzipStream = new GZipStream(compressMs, CompressionMode.Compress, true))
                            {
                                byte[] upCompressDatas = formatterMs.ToArray();
                                gzipStream.Write(upCompressDatas, 0, upCompressDatas.Length);
                            }
                            byte[] compressDatas = compressMs.ToArray();
                            return Convert.ToBase64String(compressDatas, 0, compressDatas.Length);
                        }
                    }
                }
                catch (Exception e)
                {
                    throw new Exception("err:204 Compress DataTable cause Error", e);
                }
            }

        }
        /// <summary>
        /// 解压缩DataTable对象并反序列化
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static DataTable DecompressToDataTable(this string str)
        {
            if (string.IsNullOrEmpty(str))
                return null;
            else
            {
                try
                {
                    // 以下代码是解压和反序列化
                    byte[] buffer1 = Convert.FromBase64String(str);

                    using (MemoryStream ms2 = new MemoryStream(buffer1, 0, buffer1.Length))
                    {
                        ms2.Position = 0;
                        // 解压
                        using (GZipStream gzipStream2 = new GZipStream(ms2, CompressionMode.Decompress))
                        {
                            using (MemoryStream ms3 = new MemoryStream())
                            {
                                byte[] buffer2 = new byte[4096];
                                int offset = 0;
                                while ((offset = gzipStream2.Read(buffer2, 0, buffer2.Length)) != 0)
                                {
                                    ms3.Write(buffer2, 0, offset);
                                }
                                BinaryFormatter formatter1 = new BinaryFormatter();
                                ms3.Position = 0;
                                // 反序列化
                                return (DataTable)formatter1.Deserialize(ms3);
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    throw new Exception("err:205 Decompress DataTable cause Error", e);
                }
            }
        }
    }
}
